﻿#include "customzoomchart.h"
#include <QLineSeries>
#include <QDateTime>
#include <QDateTimeAxis>
#include <QValueAxis>
#include <QDebug>
#include <QLegendMarker>

CustomZoomChart::CustomZoomChart(QWidget* pParent /*= nullptr*/)
    : QChartView(pParent)
    , m_bMiddleButtonPressed(false)
    , m_tipTool(0)
    , m_coordX(0)
    , m_coordY(0)
    , m_oPrePos(0, 0)
{
    m_splinesSeriesGroup.clear();
    m_axesGroup.clear();

}

CustomZoomChart::~CustomZoomChart()
{


}

void CustomZoomChart::mouseMoveEvent(QMouseEvent *pEvent)
{
    if (m_bMiddleButtonPressed)
    {
        QPoint oDeltaPos = pEvent->pos() - m_oPrePos;
        this->chart()->scroll(-oDeltaPos.x(), oDeltaPos.y());
        m_oPrePos = pEvent->pos();
    }
    __super::mouseMoveEvent(pEvent);
}

void CustomZoomChart::mousePressEvent(QMouseEvent *pEvent)
{
    if (pEvent->button() == Qt::MiddleButton)
    {
        m_bMiddleButtonPressed = true;
        m_oPrePos = pEvent->pos();
        this->setCursor(Qt::OpenHandCursor);
        }else if (pEvent->button() == Qt::RightButton)
    {
        if(m_tipTools.count() > 0)
        {
            for(auto tipTool : m_tipTools)
            {
                m_tipTools.removeOne(tipTool);
                delete  tipTool;
            }
        }

    }
    __super::mousePressEvent(pEvent);
}

void CustomZoomChart::mouseReleaseEvent(QMouseEvent *pEvent)
{
    if (pEvent->button() == Qt::MiddleButton)
    {
    m_bMiddleButtonPressed = false;
    this->setCursor(Qt::ArrowCursor);
    }
    __super::mouseReleaseEvent(pEvent);
}

void CustomZoomChart::wheelEvent(QWheelEvent *pEvent)
{
    qreal rVal = std::pow(0.999, pEvent->delta()); //  Set scale
    //1. Read the basic information of the view
    QRectF oPlotAreaRect = this->chart()->plotArea();
    QPointF oCenterPoint = oPlotAreaRect.center();
    //2. Horizontal adjustment
    oPlotAreaRect.setWidth(oPlotAreaRect.width() * rVal);
    //3. Vertical adjustment
    oPlotAreaRect.setHeight(oPlotAreaRect.height() * rVal);
    //4.1 calculate the viewpoint, keep the viewpoint unchanged, and zoom around the center
    //QPointF oNewCenterPoint(oCenterPoint);
    //4.2 calculate the viewpoint and move the position clicked by the mouse to the center of the window
    //QPointF oNewCenterPoint(pEvent->pos());
    //4.3 calculate the viewpoint and keep the position clicked by the mouse as still as possible (there is a little error in proportional conversion)
    QPointF oNewCenterPoint(2 * oCenterPoint - pEvent->pos() - (oCenterPoint - pEvent->pos()) / rVal);
    //5. Set viewpoint
    oPlotAreaRect.moveCenter(oNewCenterPoint);
    //6. Submit zoom adjustment
    this->chart()->zoomIn(oPlotAreaRect);
    __super::wheelEvent(pEvent);
}

void CustomZoomChart::attachAxis(int& themeType)
{
    // add to chart
    if(m_splinesSeriesGroup.size()>0)
    {
        QDateTimeAxis *axisX = new QDateTimeAxis;
        axisX->setTickCount(m_chartConfig.xAixsTickPoints);
        axisX->setFormat(tr("hh:mm:ss"));
        axisX->setTitleText(tr("时间"));
        this->chart()->addAxis(axisX, Qt::AlignBottom);
        m_axesGroup.append(axisX);

        for(auto& series : m_splinesSeriesGroup)
        {

            if(m_chartConfig.enableOpenGL)
            {
                series->setUseOpenGL(true);
            }

            this->chart()->addSeries(series);
            series->attachAxis(axisX);

            QValueAxis *axisY = new QValueAxis;
            axisY->setTickCount(m_chartConfig.yAxisTickPoints);
            axisY->setLabelFormat(tr("%d"));
            auto yName = series->name();
            axisY->setTitleText(yName);
            this->chart()->addAxis(axisY, Qt::AlignLeft);
            series->attachAxis(axisY);
            m_axesGroup.append(axisY);

        }

        this->chart()->legend()->setVisible(true);
        this->chart()->setTitle(tr("数据总览"));
        this->chart()->setTheme(static_cast<QChart::ChartTheme>(themeType));

    }
}

void CustomZoomChart::attachTipTool(QSplineSeries *series)
{
//    setRenderHint(QPainter::Antialiasing); //high effect slow progress

//    m_coordX = new QGraphicsSimpleTextItem(this->chart());
//    m_coordX->setPos(this->chart()->size().width()/2 - 50, this->chart()->size().height());
//    m_coordX->setText(tr("时间: "));
//    m_coordY = new QGraphicsSimpleTextItem(this->chart());
//    m_coordY->setPos(this->chart()->size().width()/2 + 50, this->chart()->size().height());
//    m_coordY->setText(tr("数值: "));

    connect(series, &QLineSeries::clicked, this, &CustomZoomChart::keepCallout);
    connect(series, &QLineSeries::hovered, this, &CustomZoomChart::tooltip);

    connect(series, &QSplineSeries::clicked, this, &CustomZoomChart::keepCallout);
    connect(series, &QSplineSeries::hovered, this, &CustomZoomChart::tooltip);

    this->setMouseTracking(true);

}

void CustomZoomChart::setChartConfig(const ConfigStruct &chartConfig)
{
    m_chartConfig = chartConfig;
}

void CustomZoomChart::removeSeries()
{
    if(m_splinesSeriesGroup.count()>0)
    {
        for(auto &series : m_splinesSeriesGroup)
        {
            this->chart()->removeSeries(series);
            m_splinesSeriesGroup.removeOne(series);
            delete series;
        }


    }

    if(m_axesGroup.count()>0)
    {
        for(auto &axis : m_axesGroup)
        {
            this->chart()->removeAxis(axis);
            m_axesGroup.removeOne(axis);
            delete axis;
        }
    }

    this->chart()->setTitle("");



}

void CustomZoomChart::removeTips()
{
    if(m_tipTools.count()>0)
    {
        for(auto tip : m_tipTools)
        {
            m_tipTools.removeOne(tip);
            delete tip;

        }
    }

}

void CustomZoomChart::connectMarkers()
{
    if(m_splinesSeriesGroup.count()>0)
    {
        const auto markers = this->chart()->legend()->markers();
        for (QLegendMarker *marker : markers) {
            // Disconnect possible existing connection to avoid multiple connections
            QObject::disconnect(marker, &QLegendMarker::clicked,
                                this, &CustomZoomChart::handleMarkerClicked);
            QObject::connect(marker, &QLegendMarker::clicked, this, &CustomZoomChart::handleMarkerClicked);
        }
    }

}

void CustomZoomChart::disconnectMarkers()
{
    if(m_splinesSeriesGroup.count()>0)
    {
        const auto markers = this->chart()->legend()->markers();
        for (QLegendMarker *marker : markers) {
            QObject::disconnect(marker, &QLegendMarker::clicked,
                                this, &CustomZoomChart::handleMarkerClicked);
        }
    }

}

void CustomZoomChart::handleMarkerClicked()
{
    //![3]
        QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
        Q_ASSERT(marker);
    //![3]

    //![4]
        switch (marker->type())
    //![4]
        {
            case QLegendMarker::LegendMarkerTypeXY:
            {
    //![5]
            // Toggle visibility of series
            if(marker->series()->isVisible())
            {
                auto axes = marker->series()->attachedAxes();

                axes.at(1)->setVisible(false);

            }else{

                auto axes = marker->series()->attachedAxes();

                axes.at(1)->setVisible(true);

            }

            marker->series()->setVisible(!marker->series()->isVisible());

            // Turn legend marker back to visible, since hiding series also hides the marker
            // and we don't want it to happen now.
            marker->setVisible(true);


    //![5]

    //![6]
            // Dim the marker, if series is not visible
            qreal alpha = 1.0;

            if (!marker->series()->isVisible())
                alpha = 0.5;

            QColor color;
            QBrush brush = marker->labelBrush();
            color = brush.color();
            color.setAlphaF(alpha);
            brush.setColor(color);
            marker->setLabelBrush(brush);

            brush = marker->brush();
            color = brush.color();
            color.setAlphaF(alpha);
            brush.setColor(color);
            marker->setBrush(brush);

            QPen pen = marker->pen();
            color = pen.color();
            color.setAlphaF(alpha);
            pen.setColor(color);
            marker->setPen(pen);

    //![6]
            break;
            }
        default:
            {
            qDebug() << "Unknown marker type";
            break;
            }
        }
}

void CustomZoomChart::keepCallout()
{
    QAbstractSeries *series = qobject_cast<QAbstractSeries *>(sender());
    if(m_tipTools.count() < m_chartConfig.maxTipPoints)
    {
        m_tipTools.append(m_tipTool);

        m_tipTool = new TipNotify(this->chart(), series);
        m_tipTool->hide();

    }else{

        return;
    }

}

void CustomZoomChart::tooltip(QPointF point, bool state)
{
    QAbstractSeries *series = qobject_cast<QAbstractSeries *>(sender());
    if (m_tipTool == 0){
        m_tipTool = new TipNotify(this->chart(), series);
    }
    if (state) {

        qint64 xTime = qint64(point.x());

        QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(xTime);

//        qDebug()<<"QDateTime is "<< dateTime;

        auto xValue =dateTime.toString("hh:mm:ss");

        m_tipTool->setSeries(series);
        m_tipTool->setText(QString("X: %1 \nY: %2 ").arg(xValue).arg(point.y()));
        m_tipTool->setAnchor(point);
        m_tipTool->setZValue(11);
        m_tipTool->updateGeometry();
        m_tipTool->show();
    } else {
        m_tipTool->hide();
    }
}

bool CustomZoomChart::setChartView(QVector<QStringList> &originData)
{


    //add data to series
    for(QVector<QStringList>::iterator it = originData.begin();it != originData.end(); it++)
    {
        decltype (it->size()) sizeCount = 0;
        if(it == originData.begin() && it->size()>0)
        {
            qDebug()<<"first";
            sizeCount = it->size();
            decltype (it->size()) i = 3;
            while(i < sizeCount)
            {
                auto series = new QSplineSeries();
                series->setName(it->at(i));
                m_splinesSeriesGroup.append(series);
                i++;
            }


        }else{

            decltype (it->size()) j = 3;
            sizeCount = it->size();
            while(j<sizeCount)
            {
                QString dateTime = it->at(0) + " " + it->at(1);
                auto time = QDateTime::fromString(dateTime, "yyyy/MM/dd hh:mm:ss");
                qreal value = it->at(j).toDouble();
                m_splinesSeriesGroup.at(j-3)->append(time.toMSecsSinceEpoch(),value);
                j++;
            }

        }

    }

    int themeType = m_chartConfig.chartTheme;
    attachAxis(themeType);
    this->chart()->setAcceptHoverEvents(true);

    this->setMouseTracking(true);

    for(auto serie : m_splinesSeriesGroup)
    {
        attachTipTool(serie);
    }


    return true;
}
